package com.muyu.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.muyu.common.core.constant.Constants;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.enums.OrderStatus;
import com.muyu.common.core.enums.PayStatus;
import com.muyu.system.Vo.AccountLogVO;
import com.muyu.system.Vo.AccountVO;
import com.muyu.system.Vo.SecurityRefundVO;
import com.muyu.system.danmo.dto.PayDTO;
import com.muyu.system.danmo.dto.PaymentCallBackResult;
import com.muyu.system.danmo.dto.RefundDTO;
import com.muyu.system.danmo.enums.RefundStatus;
import com.muyu.system.danmo.fegin.PayFeign;
import com.muyu.system.danmo.vo.PayVO;
import com.muyu.system.danmo.vo.RefundResultServiceVO;
import com.muyu.system.danmo.vo.RefundResultVO;
import com.muyu.system.domain.*;
import com.muyu.system.dto.AccountLogDTO;
import com.muyu.system.dto.PremiumPayDTO;
import com.muyu.system.dto.SecurityRefundDTO;
import com.muyu.system.enums.ChangeTypeEnum;
import com.muyu.system.mapper.*;
import com.muyu.system.service.SecurityDepositService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

import static com.muyu.common.core.constant.CommonConstant.*;
import static com.muyu.common.core.constant.Constants.MCH_CODE;

/**
 * @author Administrator
 */
@Service
@RequiredArgsConstructor
public class SecurityDepositServiceImpl implements SecurityDepositService {

    private final SecurityDepositAccountMapper securityDepositAccountMapper;

    private final SecurityDepositAccountLogMapper securityDepositAccountLogMapper;

    private final SecurityDepositOrderMapper securityDepositOrderMapper;

    private final DmShoppingStoreMapper dmShoppingStoreMapper;

    private final PayFeign payFeign;

    private final PremiumAccountMapper  premiumAccountMapper;

    private final PremiumOrderMapper premiumOrderMapper;


    @Override
    public AccountVO account(Long storeId) {
        AccountVO accountVO = new AccountVO();
        SecurityDepositAccount one = new LambdaQueryChainWrapper<>(securityDepositAccountMapper).eq(SecurityDepositAccount::getStoreId, storeId).one();
        BeanUtil.copyProperties(one, accountVO);
        return accountVO;
    }

    @Override
    public IPage<AccountLogVO> accountLog(AccountLogDTO accountLogDTO) {
        Page<SecurityDepositAccountLog> page = new LambdaQueryChainWrapper<>(securityDepositAccountLogMapper)
                .eq(SecurityDepositAccountLog::getAccountId, accountLogDTO.getAccountId())
                .orderByDesc(SecurityDepositAccountLog::getCreateTime)
                .page(new Page<>(accountLogDTO.getPageNum(), accountLogDTO.getPageSize()));
        return page.convert(a -> {
            AccountLogVO accountLogVO = new AccountLogVO();
            BeanUtil.copyProperties(a, accountLogVO);
            return accountLogVO;
        });
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public PayVO pay(com.muyu.system.dto.PayDTO payDTO) {
        SecurityDepositAccount account = securityDepositAccountMapper.selectById(payDTO.getAccountId());
        int amount = account.getSecurityDeposit() - account.getAmount();
        if(amount <= 0){
            throw new RuntimeException("无需缴纳！");
        }
        List<SecurityDepositOrder> list = new LambdaQueryChainWrapper<>(securityDepositOrderMapper).eq(SecurityDepositOrder::getAccountId, payDTO.getAccountId())
                .eq(SecurityDepositOrder::getPayStatus, PayStatus.PENDING).list();
        if(!list.isEmpty()){
            throw new RuntimeException("存在未支付订单！");
        }
        SecurityDepositOrder securityDepositOrder = new SecurityDepositOrder();
        securityDepositOrder.setAccountId(payDTO.getAccountId());
        securityDepositOrder.setStoreId(account.getStoreId());
        securityDepositOrder.setUserId(payDTO.getUserId());
        securityDepositOrder.setOrderSn(SECURITY_DEPOSIT_TOP + RandomUtil.randomNumbers(16));
        securityDepositOrder.setPayType(payDTO.getPayType());
        securityDepositOrder.setPayAmount(amount);


        PayDTO pay = new PayDTO();
        pay.setProjectName("保证金");
        pay.setMchCode(MCH_CODE);
        pay.setPayMethod(securityDepositOrder.getPayType());
        pay.setBizOrderNo(securityDepositOrder.getOrderSn());
        pay.setDescription("保证金");
        pay.setTotalAmount((long) amount);
        pay.setTimeExpire(DateUtil.offsetMinute(DateUtil.date(), 10).toLocalDateTime());
        pay.setPayTel(payDTO.getTel());
        Result<PayVO> result = payFeign.pay(pay);
        if (result.getCode() != 200) {
            throw new RuntimeException(result.getMsg());
        }
        securityDepositOrder.setPayOrderNo(result.getData().getOrderNo());
        securityDepositOrder.setPayStatus(PayStatus.PENDING);
        securityDepositOrderMapper.insert(securityDepositOrder);
        return result.getData();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public PayVO premiumPay(PremiumPayDTO payDTO) {
        PremiumAccount premiumAccount = premiumAccountMapper.selectById(payDTO.getAccountId());
        DmShoppingStore dmShoppingStore = dmShoppingStoreMapper.selectById(premiumAccount.getStoreId());
        if(premiumAccount.getAmount()  >= dmShoppingStore.getType().getPremium()){
            throw new RuntimeException("无需缴纳！");
        }
        List<PremiumOrder> list = new LambdaQueryChainWrapper<>(premiumOrderMapper).eq(PremiumOrder::getAccountId, payDTO.getAccountId())
                .eq(PremiumOrder::getPayStatus, PayStatus.PENDING).list();
        if(!list.isEmpty()){
            throw new RuntimeException("存在未支付订单！");
        }
        PremiumOrder premiumOrder = new PremiumOrder();
        premiumOrder.setAccountId(payDTO.getAccountId());
        premiumOrder.setStoreId(premiumAccount.getStoreId());
        premiumOrder.setUserId(payDTO.getUserId());
        premiumOrder.setOrderSn(PREMIUM_TOP + RandomUtil.randomNumbers(16));
        premiumOrder.setPayType(payDTO.getPayType());
        premiumOrder.setPayAmount(payDTO.getAmount());


        PayDTO pay = new PayDTO();
        pay.setProjectName("手续费");
        pay.setMchCode(MCH_CODE);
        pay.setPayMethod(premiumOrder.getPayType());
        pay.setBizOrderNo(premiumOrder.getOrderSn());
        pay.setDescription("手续费");
        pay.setTotalAmount((long) premiumOrder.getPayAmount());
        pay.setTimeExpire(DateUtil.offsetMinute(DateUtil.date(), 10).toLocalDateTime());
        pay.setPayTel(payDTO.getTel());
        Result<PayVO> result = payFeign.pay(pay);
        if (result.getCode() != 200) {
            throw new RuntimeException(result.getMsg());
        }
        premiumOrder.setPayOrderNo(result.getData().getOrderNo());
        premiumOrder.setPayStatus(PayStatus.PENDING);
        premiumOrderMapper.insert(premiumOrder);
        return result.getData();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void payResultsHandle(PaymentCallBackResult paymentCallBackResult) {
        SecurityDepositOrder one = new LambdaQueryChainWrapper<>(securityDepositOrderMapper)
                .eq(SecurityDepositOrder::getOrderSn, paymentCallBackResult.getBizOrderNo())
                .eq(SecurityDepositOrder::getPayStatus, PayStatus.PENDING).one();
        if(one == null){
            return;
        }
        one.setPayStatus(paymentCallBackResult.getStatus());
        one.setPayTime(paymentCallBackResult.getCompletedTime());
        securityDepositOrderMapper.updateById(one);
        if(one.getPayStatus().equals(PayStatus.SUCCESS)){
            SecurityDepositAccount securityDepositAccount = securityDepositAccountMapper.selectById(one.getAccountId());
            Integer amount = securityDepositAccount.getAmount();
            // 增加余额
            securityDepositAccount.setAmount(amount + one.getPayAmount());
            securityDepositAccountMapper.updateById(securityDepositAccount);
            // 增加日志
            SecurityDepositAccountLog securityDepositAccountLog = new SecurityDepositAccountLog();
            securityDepositAccountLog.setAccountId(one.getAccountId());
            securityDepositAccountLog.setStoreId(one.getStoreId());
            securityDepositAccountLog.setChangeAfter(securityDepositAccount.getAmount());
            securityDepositAccountLog.setChangeAmount(one.getPayAmount());
            securityDepositAccountLog.setChangeBefore(amount);
            securityDepositAccountLog.setChangeType(ChangeTypeEnum.RECHARGE);
            securityDepositAccountLogMapper.insert(securityDepositAccountLog);
            updateStoreState(securityDepositAccount.getStoreId());
        }
    }


    /**
     * 判断当前商铺是否都缴费完毕
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void updateStoreState(Long storeId){
        SecurityDepositAccount securityDepositAccount = new LambdaQueryChainWrapper<>(securityDepositAccountMapper).eq(SecurityDepositAccount::getStoreId, storeId).one();
        // 保证金判断是否已经缴纳完毕
        if(securityDepositAccount.getAmount() >= securityDepositAccount.getSecurityDeposit()){
            DmShoppingStore dmShoppingStore = dmShoppingStoreMapper.selectById(storeId);
            PremiumAccount premiumAccount = new LambdaQueryChainWrapper<>(premiumAccountMapper).eq(PremiumAccount::getStoreId, storeId).one();
            if(premiumAccount.getAmount() >= dmShoppingStore.getType().getPremium()){
                dmShoppingStore.setState(1L);
                dmShoppingStoreMapper.updateById(dmShoppingStore);
            }
        }
    }




    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public SecurityRefundVO securityRefund(SecurityRefundDTO securityRefundDTO) {
        Long count = new LambdaQueryChainWrapper<>(securityDepositOrderMapper).eq(SecurityDepositOrder::getAccountId, securityRefundDTO.getAccountId())
                .eq(SecurityDepositOrder::getRefundStatus, PayStatus.PENDING).count();
        if(count > 0){
            throw new RuntimeException("存在退款中的订单！");
        }
        SecurityDepositAccount securityDepositAccount = securityDepositAccountMapper.selectById(securityRefundDTO.getAccountId());
        if(securityDepositAccount == null){
            throw new RuntimeException("账户不存在！");
        }
        // 店铺状态必须时 关闭
        DmShoppingStore dmShoppingStore = dmShoppingStoreMapper.selectById(securityDepositAccount.getStoreId());
        if(!dmShoppingStore.getState().equals(2L)){
            throw new RuntimeException("当前商户状态不是关闭状态");
        }
        Integer amount = securityDepositAccount.getAmount();
        // 查询大于退款金额的充值订单
        List<SecurityDepositOrder> list = new LambdaQueryChainWrapper<>(securityDepositOrderMapper).eq(SecurityDepositOrder::getAccountId, securityRefundDTO.getAccountId())
                .isNull(SecurityDepositOrder::getRefundOrderSn).eq(SecurityDepositOrder::getPayAmount, amount)
                .eq(SecurityDepositOrder::getPayStatus, PayStatus.SUCCESS)
                .orderByAsc(SecurityDepositOrder::getPayTime)
                .list();
        if(list.isEmpty()){
            throw new RuntimeException("没有找到充值订单！");
        }
        SecurityDepositOrder securityDepositOrder = list.get(0);
        securityDepositOrder.setRefundOrderSn(REFUND_SECURITY_DEPOSIT_TOP + RandomUtil.randomNumbers(16));

        RefundDTO refundDTO = new RefundDTO();
        refundDTO.setRefundBizOrderNo(securityDepositOrder.getRefundOrderSn());
        refundDTO.setOrderNo(securityDepositOrder.getPayOrderNo());
        Result<RefundResultVO> refund = payFeign.refund(refundDTO);
        if(refund.getCode() != Constants.SUCCESS){
            throw new RuntimeException("调用支付订单退款失败");
        }
        RefundResultVO data = refund.getData();
        securityDepositOrder.setRefundStatus(data.getStatus());
        securityDepositOrder.setRefundTime(data.getCompletedTime());
        securityDepositOrder.setPayRefundOrderNo(data.getRefundOrderNo());
        securityDepositOrderMapper.updateById(securityDepositOrder);
        if(data.getStatus().equals(PayStatus.SUCCESS)){
            // 修改账户余额
            securityDepositAccount.setAmount(0);
            securityDepositAccountMapper.updateById(securityDepositAccount);
            // 增加日志
            SecurityDepositAccountLog securityDepositAccountLog = new SecurityDepositAccountLog();
            securityDepositAccountLog.setAccountId(securityDepositAccount.getId());
            securityDepositAccountLog.setStoreId(securityDepositAccount.getStoreId());
            securityDepositAccountLog.setChangeAfter(0);
            securityDepositAccountLog.setChangeAmount(amount);
            securityDepositAccountLog.setChangeBefore(amount);
            securityDepositAccountLog.setChangeType(ChangeTypeEnum.REFUND);
            securityDepositAccountLogMapper.insert(securityDepositAccountLog);
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void refundResultsHandle(RefundResultServiceVO refundResultServiceVO) {
        // 查询保证金的充值订单
        SecurityDepositOrder securityDepositOrder = new LambdaQueryChainWrapper<>(securityDepositOrderMapper)
                .eq(SecurityDepositOrder::getRefundOrderSn, refundResultServiceVO.getRefundBizOrderNo())
                .one();
        if(securityDepositOrder == null){
            throw new RuntimeException("未找到该订单！");
        }
        securityDepositOrder.setRefundStatus(refundResultServiceVO.getStatus());
        securityDepositOrder.setRefundTime(refundResultServiceVO.getCompletedTime());
        securityDepositOrder.setPayRefundOrderNo(refundResultServiceVO.getRefundOrderNo());
        securityDepositOrderMapper.updateById(securityDepositOrder);
        if(refundResultServiceVO.getStatus().equals(PayStatus.SUCCESS)){
            SecurityDepositAccount securityDepositAccount = securityDepositAccountMapper.selectById(securityDepositOrder.getAccountId());
            Integer amount = securityDepositAccount.getAmount();
            // 修改账户余额
            securityDepositAccount.setAmount(0);
            securityDepositAccountMapper.updateById(securityDepositAccount);
            // 增加日志
            SecurityDepositAccountLog securityDepositAccountLog = new SecurityDepositAccountLog();
            securityDepositAccountLog.setAccountId(securityDepositOrder.getAccountId());
            securityDepositAccountLog.setStoreId(securityDepositOrder.getStoreId());
            securityDepositAccountLog.setChangeAfter(0);
            securityDepositAccountLog.setChangeAmount(amount);
            securityDepositAccountLog.setChangeBefore(amount);
            securityDepositAccountLog.setChangeType(ChangeTypeEnum.REFUND);
            securityDepositAccountLogMapper.insert(securityDepositAccountLog);
        }
    }

    @Override
    public void premiumPayResults(PaymentCallBackResult paymentCallBackResult) {
        PremiumOrder one = new LambdaQueryChainWrapper<>(premiumOrderMapper).eq(PremiumOrder::getOrderSn, paymentCallBackResult.getBizOrderNo())
                .eq(PremiumOrder::getPayStatus, PayStatus.PENDING).one();
        if(one == null){
            return;
        }
        one.setPayStatus(paymentCallBackResult.getStatus());
        one.setPayTime(paymentCallBackResult.getCompletedTime());
        premiumOrderMapper.updateById(one);
        if(one.getPayStatus().equals(PayStatus.SUCCESS)){
            PremiumAccount account = premiumAccountMapper.selectById(one.getAccountId());
            Integer amount = account.getAmount();
            // 增加余额
            account.setAmount(amount + one.getPayAmount());
            premiumAccountMapper.updateById(account);
            updateStoreState(account.getStoreId());
        }

    }
}
